﻿// ----------------------------------------------------------------------------
// <copyright file="Category.cs" company="Microsoft Corporation">
//   Copyright Microsoft Corporation. All Rights Reserved. This code released under the terms of the Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) This is sample code only, do not use in production environments.
// </copyright>
// ----------------------------------------------------------------------------

namespace Microsoft.ALMRangers.VsarTreasureMap.WindowsStoreApp.ViewModels
{
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using Microsoft.ALMRangers.VsarTreasureMap.WindowsStoreApp.Models;
    using Microsoft.ALMRangers.VsarTreasureMap.WindowsStoreApp.MVVMSupport;
    using Windows.ApplicationModel.DataTransfer;
    using Windows.Storage.Streams;
    using Windows.UI.StartScreen;

    /// <summary>
    /// Object representation of a Category
    /// </summary>
    public class Category : IShare, INotifyPropertyChanged
    {
        private string categoryTitle;

        /// <summary>
        /// The filtering option
        /// </summary>
        private FilteringOptions filteringOption = FilteringOptions.None;

        /// <summary>
        /// The category
        /// </summary>
        private Models.Category category;

        /// <summary>
        /// Initializes a new instance of the <see cref="Category" /> class.  This class is the view model
        /// for the Category page.
        /// </summary>
        /// <param name="id">Unique identifier for this category.</param>
        public Category(int id)
        {
            this.GoBack = new Command(() =>
            {
                Navigation.GoBack();
            });

            this.GoToHome = new Command(() =>
            {
                Navigation.Navigate(typeof(Views.TreasureMapPage));
            });

            this.PinCategory = new Command(this.PinCategoryTile);

            this.ToggleFavourite = new Command(() =>
            {
                Models.Favourites.ToggleFavourite(this.ID, FavouriteType.Category);
                RaisePropertyChanged("IsFavourite");
            });

            this.category = App.Database.Categories.Single(_ => _.Id == id);
            this.ID = id;
            this.categoryTitle = this.category.Name;
            this.CategoryImage = this.category.Image;
            this.CategoryDescription = this.category.Description;
            this.Projects = new ObservableCollection<Project>();
            this.LoadProjects();

            this.LaunchSearch = new Command(() =>
            {
                Windows.ApplicationModel.Search.SearchPane.GetForCurrentView().Show();
            });

            this.ApplyFilter = new Command<string>(this.ApplyFilterOption);

            DataTransferManager.GetForCurrentView().DataRequested += this.Category_DataRequested;
        }

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Enum FilteringOptions
        /// </summary>
        private enum FilteringOptions
        {
            /// <summary>
            /// The none
            /// </summary>
            None,

            /// <summary>
            /// The by completed
            /// </summary>
            ByCompleted,

            /// <summary>
            /// The by not completed
            /// </summary>
            ByNotCompleted
        }

        /// <summary>
        /// Gets or sets the Category's full description
        /// </summary>
        /// <value>The category description.</value>
        public string CategoryDescription { get; set; }

        /// <summary>
        /// Gets or sets the Category's image uri
        /// </summary>
        /// <value>The category image.</value>
        public string CategoryImage { get; set; }

        /// <summary>
        /// Gets the Category's Title
        /// </summary>
        /// <value>The category title.</value>
        public string CategoryTitle
        {
            get
            {
                var result = this.categoryTitle;
                switch (this.filteringOption)
                {
                    case FilteringOptions.ByCompleted:
                        {
                            result += " - filtered By Completed";
                            break;
                        }

                    case FilteringOptions.ByNotCompleted:
                        {
                            result += " - filtered By Not Completed";
                            break;
                        }

                    case FilteringOptions.None:
                    default:
                        {
                            // nothing
                            break;
                        }
                }

                return result;
            }

            private set
            {
                this.categoryTitle = value;
            }
        }

        /// <summary>
        /// Gets the command for the back button
        /// </summary>
        /// <value>The go back.</value>
        public Command GoBack { get; private set; }

        /// <summary>
        /// Gets the command for the home button
        /// </summary>
        /// <value>The go to home.</value>
        public Command GoToHome { get; private set; }

        /// <summary>
        /// Gets a value indicating whether this instance is favourite.
        /// </summary>
        /// <value><c>true</c> if this instance is favourite; otherwise, <c>false</c>.</value>
        public bool IsFavourite
        {
            get
            {
                return Models.Favourites.IsFavourite(this.ID, FavouriteType.Category);
            }
        }

        /// <summary>
        /// Gets the pin category.
        /// </summary>
        /// <value>The pin category.</value>
        public Command PinCategory { get; private set; }

        /// <summary>
        /// Gets the List of Guidance of which are projects.
        /// </summary>
        /// <value>The projects.</value>
        public ObservableCollection<Project> Projects { get; private set; }

        /// <summary>
        /// Gets the toggle favourite.
        /// </summary>
        /// <value>The toggle favourite.</value>
        public Command ToggleFavourite { get; private set; }

        /// <summary>
        /// Gets or sets the apply filter.
        /// </summary>
        /// <value>The apply filter.</value>
        public Command<string> ApplyFilter { get; set; }

        /// <summary>
        /// Gets or sets the launch search.
        /// </summary>
        /// <value>The launch search.</value>
        public Command LaunchSearch { get; set; }

        /// <summary>
        /// The internally used identifier for the selected category.
        /// </summary>
        /// <value>The ID.</value>
        private int ID { get; set; }

        /// <summary>
        /// Sharing event handler that is called when a user attempts to share from this page.
        /// </summary>
        /// <param name="sender">The parameter is not used.</param>
        /// <param name="args">The parameter is not used.</param>
        public void Category_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            var shareContent = @"Downloads: ??
App in Windows Store http://aka.ms/vsartmapapp 
Source code in CodePlex http://aka.ms/vsartmap";

            args.Request.Data.SetText(shareContent);

            // For email sharing
            args.Request.Data.Properties.Title = "ALM Readiness Treasure Map";
            args.Request.Data.Properties.Description = "The ALM Readiness treasure map sample application provides a catalogue (treasure map) of the available ALM readiness content, guiding you through the process of becoming proficient in ALM practices for Visual Studio.";

            var htmlExample = string.Format(CultureInfo.InvariantCulture, "<h1>{0}</h1><br>{1}<br><img src='{2}'></img>{3}", this.categoryTitle, this.CategoryDescription, "Image.png", shareContent.Replace(Environment.NewLine, "<br>"));

            args.Request.Data.SetHtmlFormat(HtmlFormatHelper.CreateHtmlFormat(htmlExample));

            // Because the HTML contains a local image, we need to add it to the ResourceMap.
            RandomAccessStreamReference streamRef =
                 RandomAccessStreamReference.CreateFromUri(new Uri(this.CategoryImage));
            args.Request.Data.ResourceMap["Image.png"] = streamRef;
        }

        /// <summary>
        /// Unregisters charm events as to not have multiple instances of the same handler for the same raised event.
        /// </summary>
        public void Unregister()
        {
            DataTransferManager.GetForCurrentView().DataRequested -= this.Category_DataRequested;
        }

        /// <summary>
        /// Handles navigating to a specified project
        /// </summary>
        /// <param name="value">The project to navigate to.</param>
        public void NavigateToSelectedProject(Models.Project value)
        {           
            var index = this.Projects.IndexOf(value);
            var parameter = Tuple.Create(this.ID, this.Projects[index]);
            Navigation.Navigate(typeof(Microsoft.ALMRangers.VsarTreasureMap.WindowsStoreApp.Views.Projects), parameter);
        }

        /// <summary>
        /// Loads the projects.
        /// </summary>
        private void LoadProjects()
        {
            this.Projects.Clear();

            foreach (var item in this.category.Projects)
            {
                switch (this.filteringOption)
                {
                    case FilteringOptions.ByCompleted:
                        {
                            var done = App.Database.StatusManager.GetCompletedDocumentCount(item.Id);
                            var total = App.Database.StatusManager.GetProjectDocumentCount(item.Id);
                            if (done == total)
                            {
                                this.Projects.Add(item);
                            }

                            break;
                        }

                    case FilteringOptions.ByNotCompleted:
                        {
                            var done = App.Database.StatusManager.GetCompletedDocumentCount(item.Id);
                            var total = App.Database.StatusManager.GetProjectDocumentCount(item.Id);
                            if (done != total)
                            {
                                this.Projects.Add(item);
                            }

                            break;
                        }

                    default:
                        {
                            this.Projects.Add(item);
                            break;
                        }
                }
            }
        }

        /// <summary>
        /// Pins the category tile.
        /// </summary>
        private async void PinCategoryTile()
        {
            var id = string.Format("category-{0}", this.ID);
            var logo = new Uri(this.CategoryImage.Replace(".png", "-small.png"));
            var tile = new SecondaryTile(id, this.CategoryTitle, this.CategoryTitle, id, TileOptions.ShowNameOnLogo, logo);
            await tile.RequestCreateAsync();
        }

        /// <summary>
        /// Raises the property changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        private void RaisePropertyChanged(string propertyName = "")
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        /// <summary>
        /// Applies the filter option.
        /// </summary>
        /// <param name="option">The option.</param>
        private void ApplyFilterOption(string option)
        {
            this.filteringOption = (FilteringOptions)Enum.Parse(typeof(FilteringOptions), option, false);
            this.LoadProjects();
            this.RaisePropertyChanged("CategoryTitle");
        }
    }
}